package com.hly.tool.tree;

import com.matrixone.apps.domain.DomainConstants;
import com.matrixone.apps.domain.DomainObject;
import com.matrixone.apps.domain.util.MapList;
import matrix.db.Context;
import matrix.util.MatrixException;
import matrix.util.StringList;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * Copyright@ Apache Open Source Organization
 *
 * @Auther: HLY
 * @Date: 2022-09-29-11:26
 * @Description: 把后台数据 转换成树结构
 */
public class EnoviaTree
{

    public void main(Context context, String[] args)
    {
        System.out.println("--------------------------testTask---------------------------");
        try
        {
            String rootId = args[0];
            System.out.println("rootId : " + rootId);
            System.out.println();

            DomainObject rootObj = DomainObject.newInstance(context, rootId);
            System.out.println("rootObj : " + rootObj);
            System.out.println();

            StringList busList = new StringList();
            busList.add(DomainConstants.SELECT_ID);
            busList.add(DomainConstants.SELECT_NAME);
            busList.add(DomainConstants.SELECT_TYPE);
            busList.add(DomainConstants.SELECT_ORIGINATED);
            busList.add(DomainConstants.SELECT_OWNER);
            busList.add(DomainConstants.SELECT_REVISION);
            busList.add(DomainConstants.SELECT_CURRENT);
            busList.add(DomainConstants.SELECT_ORIGINATOR);
            StringList relList = new StringList();
            relList.add(DomainConstants.SELECT_FROM_ID);
            relList.add(DomainConstants.SELECT_LEVEL);
            relList.add(DomainConstants.SELECT_RELATIONSHIP_ID);

            MapList relatedObjects = rootObj.getRelatedObjects(context, "Subtask", "Task Management", busList, relList, false, true, (short) 0, null, null, 0);
            System.out.println("relatedObjects : " + relatedObjects);
            System.out.println();
            System.out.println();
            System.out.println();
            System.out.println();

            JSONArray array = toTree(relatedObjects, DomainConstants.SELECT_FROM_ID, DomainConstants.SELECT_ID, rootId);
            System.out.println("array : " + array);
            System.out.println();
            System.out.println();
            System.out.println();
            System.out.println();

        } catch (Exception e)
        {
            throw new RuntimeException(e);
        }
        System.out.println("--------------------------testTask---------------------------");

    }


    /**
     * mapList 中的map 集合中需要有 relList.add(DomainConstants.SELECT_FROM_ID);
     * 数据关系方向 是to 子集合中的所有数据
     *
     * @param array
     * @param pKey
     * @param cKey
     * @param rootId
     * @return
     * @throws Exception
     */
    public JSONArray toTree(JSONArray array, String pKey, String cKey, String rootId) throws Exception
    {
        JSONArray rarray = new JSONArray();
        try
        {
            if (array == null || array.length() == 0)
            {
                return rarray;
            }

            JSONArray level1Array = getTopArray(array, pKey, new JSONArray().put(rootId));

            for (int i = 0; i < level1Array.length(); i++)
            {
                JSONObject json_i = level1Array.getJSONObject(i);

                if (ifHasChild(array, json_i.getString(cKey), pKey))
                {
                    // 最主要的一步，递归，找到孩子节点，然后塞到Map中
                    json_i.put("children", getChildren(json_i, array, pKey, cKey));
                } else
                {
                    json_i.put("children", new JSONArray());
                }
                rarray.put(json_i);
            }

        } catch (Exception e)
        {
            e.printStackTrace();
        }

        return rarray;
    }


    /**
     * mapList 中的map 集合中需要有 relList.add(DomainConstants.SELECT_FROM_ID);
     * 数据关系方向 是to 子集合中的所有数据
     *
     * @param mapList
     * @param pKey
     * @param cKey
     * @param rootId
     * @return
     * @throws Exception
     */
    public JSONArray toTree(MapList mapList, String pKey, String cKey, String rootId) throws Exception
    {
        JSONArray rarray = new JSONArray();
        try
        {
            if (mapList == null || mapList.size() == 0)
            {
                return rarray;
            }

            MapList level1List = getTopList(mapList, pKey, StringList.create(rootId));

            for (int i = 0; i < level1List.size(); i++)
            {
                Map map_i = (Map) level1List.get(i);
                JSONObject tmpJson = mapToJsonHandlerAttr(map_i);

                if (ifHasChild(mapList, tmpJson.getString(cKey), pKey))
                {
                    // 最主要的一步，递归，找到孩子节点，然后塞到Map中
                    tmpJson.put("children", getChildren(tmpJson, mapList, pKey, cKey));
                } else
                {
                    tmpJson.put("children", new JSONArray());
                }
                rarray.put(tmpJson);
            }

        } catch (Exception e)
        {
            e.printStackTrace();
        }

        return rarray;
    }


    /**
     * 递归程序 获取子节点
     *
     * @param json
     * @param mapList
     * @param pKey
     * @param cKey
     * @return
     * @throws MatrixException
     */
    public static JSONArray getChildren(JSONObject json, MapList mapList, String pKey, String cKey) throws MatrixException
    {
        JSONArray childrenArray = new JSONArray();

        // 递归返回条件，如果没返回条件就死循环了
        if (mapList == null || mapList.isEmpty())
        {
            //没有子节点情况下
            return childrenArray;
        }

        for (int i = 0; i < mapList.size(); i++)
        {
            Map map_i = (Map) mapList.get(i);

            if (map_i.get(pKey).equals(json.get(cKey)))
            {

                JSONObject tmpJson = mapToJsonHandlerAttr(map_i);

                //  递归代码
                if (ifHasChild(mapList, tmpJson.getString(cKey), pKey))
                {
                    tmpJson.put("children", getChildren(tmpJson, mapList, pKey, cKey));
                } else
                {
                    tmpJson.put("children", new JSONArray());
                }

                childrenArray.put(tmpJson);
            }

        }

        return childrenArray;
    }


    /**
     * 递归程序 获取子节点
     *
     * @param json
     * @param array
     * @param pKey
     * @param cKey
     * @return
     * @throws MatrixException
     */
    public static JSONArray getChildren(JSONObject json, JSONArray array, String pKey, String cKey) throws MatrixException
    {
        JSONArray childrenArray = new JSONArray();

        // 递归返回条件，如果没返回条件就死循环了
        if (array == null || array.isEmpty())
        {
            //没有子节点情况下
            return childrenArray;
        }

        for (int i = 0; i < array.length(); i++)
        {
            JSONObject json_i = array.getJSONObject(i);

            if (json_i.has(pKey) && json_i.get(pKey).equals(json.get(cKey)))
            {
                //  递归代码
                if (ifHasChild(array, json_i.getString(cKey), pKey))
                {
                    json_i.put("children", getChildren(json_i, array, pKey, cKey));
                } else
                {
                    json_i.put("children", new JSONArray());
                }

                childrenArray.put(json_i);
            }

        }
        return childrenArray;
    }

    /**
     * 判断一个Map是否有子节点,加快程序运行
     *
     * @param mapList
     * @param cVal
     * @param pKey
     * @return
     */
    public static boolean ifHasChild(MapList mapList, String cVal, String pKey)
    {
        int result = 0;

        for (int i = 0; i < mapList.size(); i++)
        {
            Map map_i = (Map) mapList.get(i);
            if (map_i.get(pKey) != null && map_i.get(pKey).equals(cVal))
            {
                result++;
            }
        }
        return result > 0 ? true : false;
    }

    /**
     * 判断一个JSONObject是否有子节点,加快程序运行
     *
     * @param array
     * @param cVal
     * @param pKey
     * @return
     */
    public static boolean ifHasChild(JSONArray array, String cVal, String pKey)
    {
        int result = 0;

        for (int i = 0; i < array.length(); i++)
        {
            JSONObject json_i = array.getJSONObject(i);
            if (json_i.has(pKey) && json_i.get(pKey).equals(cVal))
            {
                result++;
            }
        }
        return result > 0 ? true : false;
    }


    /**
     * map to json
     *
     * @param map
     * @return
     * @throws MatrixException
     */
    private static JSONObject mapToJsonHandlerAttr(Map map) throws MatrixException
    {
        JSONObject json = new JSONObject();
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        JSONArray attrs = new JSONArray();
        while (iterator.hasNext())
        {
            String key = (String) iterator.next();
            String value = (String) map.get(key);
            if (key.startsWith("attribute[") && key.endsWith("]"))
            {
                JSONObject attrJson = new JSONObject();
                attrJson.put("attr", key);
                attrJson.put("val", value);
                attrs.put(attrJson);
            } else
            {
                json.put(key, value);
            }
        }
        json.put("attrs", attrs);
        return json;
    }


    /**
     * map to json
     *
     * @param map
     * @return
     * @throws MatrixException
     */
    private JSONObject mapToJsonHandlerSubAttr(Map map) throws MatrixException
    {
        JSONObject json = new JSONObject();
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        JSONArray attrs = new JSONArray();
        while (iterator.hasNext())
        {
            String key = (String) iterator.next();
            String value = (String) map.get(key);
            if (key.startsWith("attribute[") && key.endsWith("]"))
            {
                JSONObject attrJson = new JSONObject();
                key = key.substring("attribute[".length(), key.length() - 1);
                attrJson.put("attr", key);
                attrJson.put("val", value);
                attrs.put(attrJson);
            } else
            {
                json.put(key, value);
            }
        }
        json.put("attrs", attrs);
        return json;
    }


    /**
     * @param mapList
     * @param pKey
     * @param parentKeyVals
     * @return MapList
     * @Description: 获取顶层数据的集合
     * @Author HLY
     * @CreateTime 2022/9/30 9:38
     */

    public static MapList getTopList(MapList mapList, String pKey, StringList parentKeyVals)
    {
        MapList level1List = new MapList();
        for (int i = 0; i < mapList.size(); i++)
        {
            Map map_i = (Map) mapList.get(i);

            String pVal_i = (String) map_i.get(pKey);

            if (parentKeyVals.contains(pVal_i))
            {
                level1List.add(map_i);
            }
        }

        return level1List;
    }

    /**
     * @param array
     * @param pKey
     * @param parentKeyVals
     * @return MapList
     * @Author HLY
     * @CreateTime 2022/9/30 9:38
     * @Description: 获取顶层数据的集合
     */

    public static JSONArray getTopArray(JSONArray array, String pKey, JSONArray parentKeyVals)
    {
        // 第一层的的数据，在这里就是 label01 和 label02单独抽取出来，因为有时候需要单独处理，也可以将for循环的代码放到递归的位置一起处理
        JSONArray level1Array = new JSONArray();
        for (int i = 0; i < array.length(); i++)
        {
            JSONObject json_i = array.getJSONObject(i);

            String pVal_i = (String) json_i.get(pKey);

            if (parentKeyVals.toList().contains(pVal_i))
            {
                level1Array.put(json_i);
            }
        }
        return level1Array;
    }


}
